/**
 * 虚拟化节点渲染器组件
 *
 * ========== 虚拟化节点渲染原理 ==========
 *
 * 🎯 核心功能：
 * 1. 智能缓存：避免重复渲染相同内容的节点
 * 2. 绝对定位：每个节点独立定位，避免布局重排
 * 3. 按需渲染：只渲染传入的可见节点列表
 * 4. 性能监控：实时统计缓存效果和渲染性能
 *
 * 🚀 性能优势：
 * - 减少React组件创建开销
 * - 降低虚拟DOM diff计算量
 * - 避免不必要的重新渲染
 * - 提升大规模节点场景下的交互流畅度
 *
 * 🏗️ 适用场景：
 * - 大量节点需要频繁更新位置
 * - 节点内容复杂，渲染成本高
 * - 需要精确的性能控制
 */

import React, { useRef, useCallback, useEffect, useMemo } from "react";
import type { OKRNode } from "../../../types/okr";
import type { TreeLayout } from "./OKRTreeView";
import OKRNodeComponent from "./OKRNodeComponent";

/**
 * 节点渲染缓存类 - 智能缓存已渲染的React元素
 *
 * 🧠 缓存策略：
 * 1. 版本检查：基于节点数据生成版本号，数据变化时自动失效
 * 2. LRU淘汰：最近最少使用的缓存项优先被清理
 * 3. 容量控制：限制最大缓存数量，避免内存泄漏
 * 4. 访问统计：记录缓存命中率，用于性能监控
 *
 * 📊 性能收益：
 * - 避免重复渲染相同内容的节点
 * - 减少React组件创建开销
 * - 降低虚拟DOM diff计算量
 */

//  缓存原理 ：用map 通过id 记录 节点实例，然后设置最大缓存数量，超过了 则删除最久没访问到的元素。
// 二 给每个实例 设置版本 用于 失效控制； 版本号 是通过 实例中会导致状态变化的 字段 生成。 当状态变化了 版本号就会变化 ， 获取实例的是时候 拿当前状态 和 生成版本对比 如果 版本没变则 缓存命中 否则 缓存失效。 删除缓存。
class NodeRenderCache {
  // ========== 核心存储 ==========

  /** 缓存映射表：nodeId -> 缓存项 */
  private cache = new Map<
    string,
    {
      element: React.ReactElement; // 缓存的React元素
      lastUpdate: number; // 最后访问时间（用于LRU淘汰）
      version: string; // 节点数据版本号（用于失效检查）
      hitCount: number; // 命中次数（用于统计）
    }
  >();

  // ========== 配置参数 ==========

  private maxCacheSize = 1000; // 最大缓存数量
  private hitCount = 0; // 总命中次数
  private missCount = 0; // 总未命中次数

  /**
   * 获取缓存的节点元素
   * 实现LRU缓存策略：每次访问都更新访问时间
   *
   * @param nodeId 节点ID
   * @param node 节点数据（用于版本检查）
   * @param isCollapsed 节点是否折叠
   * @param isHovered 节点是否被悬浮
   * @returns 缓存的React元素，如果缓存失效或不存在则返回null
   */
  get(nodeId: string, node: OKRNode, isCollapsed: boolean, isHovered: boolean): React.ReactElement | null {
    const cached = this.cache.get(nodeId);

    // 🚫 缓存不存在
    if (!cached) {
      this.missCount++;
      return null;
    }

    // 🔍 版本检查：节点数据是否有更新（包含折叠和悬浮状态）
    const currentVersion = this.getNodeVersion(node, isCollapsed, isHovered);

    if (cached.version !== currentVersion) {
      // 📝 数据已更新，删除过期缓存
      this.cache.delete(nodeId);
      this.missCount++;

      // 📊 开发环境日志
      if (import.meta.env.DEV && import.meta.env.VITE_DEBUG_CACHE === "true") {
        console.log(`🔄 缓存失效: ${nodeId} (版本 ${cached.version} -> ${currentVersion})`);
      }

      return null;
    }

    // ✅ 缓存命中：更新访问统计
    cached.lastUpdate = Date.now(); // 更新LRU时间戳
    cached.hitCount++; // 增加命中计数
    this.hitCount++;

    return cached.element;
  }

  /**
   * 缓存节点元素
   * 实现容量控制：超出限制时自动清理最旧的缓存项
   *
   * @param nodeId 节点ID
   * @param node 节点数据
   * @param element 要缓存的React元素
   * @param isCollapsed 节点是否折叠
   * @param isHovered 节点是否被悬浮
   */
  set(nodeId: string, node: OKRNode, element: React.ReactElement, isCollapsed: boolean, isHovered: boolean): void {
    // 🧹 容量控制：如果缓存已满，先清理最旧的条目
    if (this.cache.size >= this.maxCacheSize) {
      this.evictOldest();
    }

    // 💾 存储新的缓存项
    this.cache.set(nodeId, {
      element, // React元素
      lastUpdate: Date.now(), // 当前时间作为初始访问时间
      version: this.getNodeVersion(node, isCollapsed, isHovered), // 当前数据版本（包含折叠和悬浮状态）
      hitCount: 0 // 初始命中次数为0
    });

    // 📊 开发环境日志
    if (import.meta.env.DEV && import.meta.env.VITE_DEBUG_CACHE === "true") {
      console.log(`💾 缓存存储: ${nodeId} (缓存大小: ${this.cache.size}/${this.maxCacheSize})`);
    }
  }

  /**
   * 生成节点版本标识
   * 基于关键数据字段生成版本号，任何影响渲染的数据变化都会改变版本号
   *
   * @param node 节点数据
   * @param isCollapsed 节点是否折叠
   * @param isHovered 节点是否被悬浮
   * @returns 版本标识字符串
   */
  private getNodeVersion(node: OKRNode, isCollapsed: boolean, isHovered: boolean): string {
    // 🏷️ 版本号组成：更新时间 + 进度 + 状态 + 关键结果数量 + 折叠状态 + 悬浮状态
    // 这些字段的任何变化都会影响节点的视觉呈现，必须包含在版本号中
    return `${node.updatedAt}-${node.progress}-${node.status}-${node.keyResults.length}-${isCollapsed}-${isHovered}`;
  }

  /**
   * LRU淘汰策略：清理最旧的缓存条目
   * 遍历所有缓存项，找到最久未访问的项目进行删除
   */
  private evictOldest(): void {
    let oldestKey = "";
    let oldestTime = Date.now();

    // 🔍 找出最久未访问的缓存项
    // 找到最久没有访问的缓存元素;
    this.cache.forEach((value, key) => {
      if (value.lastUpdate < oldestTime) {
        oldestTime = value.lastUpdate;
        oldestKey = key;
      }
    });

    // 🗑️ 删除最旧的缓存项
    if (oldestKey) {
      const evicted = this.cache.get(oldestKey);
      this.cache.delete(oldestKey);

      // 📊 开发环境日志
      if (import.meta.env.DEV && import.meta.env.VITE_DEBUG_CACHE === "true") {
        console.log(
          `🗑️ LRU淘汰: ${oldestKey} (命中${evicted?.hitCount}次，${Math.round((Date.now() - oldestTime) / 1000)}秒前访问)`
        );
      }
    }
  }

  /**
   * 获取缓存统计信息
   * 用于性能监控和优化决策
   */
  getStats() {
    const total = this.hitCount + this.missCount;
    const hitRate = total > 0 ? ((this.hitCount / total) * 100).toFixed(1) : "0.0";

    return {
      cacheSize: this.cache.size, // 当前缓存数量
      maxSize: this.maxCacheSize, // 最大缓存数量
      hitCount: this.hitCount, // 总命中次数
      missCount: this.missCount, // 总未命中次数
      hitRate: `${hitRate}%`, // 命中率
      memoryUsage: `${((this.cache.size / this.maxCacheSize) * 100).toFixed(1)}%` // 内存使用率
    };
  }

  /**
   * 清空所有缓存
   * 用于数据大量更新或内存清理
   */
  clear(): void {
    this.cache.clear();
    this.hitCount = 0;
    this.missCount = 0;

    if (import.meta.env.DEV) {
      console.log(`🧹 缓存已清空`);
    }
  }
}

/**
 * 虚拟化节点渲染器组件属性接口
 */
interface VirtualizedNodeRendererProps {
  /** 当前可见的节点ID列表 */
  visibleNodes: string[];
  /** 所有节点数据映射表 */
  nodes: Record<string, OKRNode>;
  /** 布局信息（节点位置） */
  layout: TreeLayout;
  /** 当前悬浮的节点ID */
  hoveredNodeId?: string;
  /** 折叠的节点ID列表 */
  collapsedNodes: string[];
  /** 节点点击回调 */
  onNodeClick?: (nodeId: string) => void;
  /** 折叠切换回调 */
  onToggleCollapse?: (nodeId: string) => void;
}

/**
 * 虚拟化节点渲染器组件 - 结合缓存机制的高性能节点渲染
 *
 * 🎨 核心特性：
 * 1. 智能缓存：避免重复渲染相同内容的节点
 * 2. 绝对定位：每个节点独立定位，避免布局重排
 * 3. 按需渲染：只渲染传入的可见节点列表
 * 4. 性能监控：实时统计缓存效果和渲染性能
 *
 * 🏗️ 适用场景：
 * - 大量节点需要频繁更新位置
 * - 节点内容复杂，渲染成本高
 * - 需要精确的性能控制
 */
const VirtualizedNodeRenderer: React.FC<VirtualizedNodeRendererProps> = ({
  visibleNodes,
  nodes,
  layout,
  hoveredNodeId,
  collapsedNodes,
  onNodeClick,
  onToggleCollapse
}) => {
  // ========== 缓存实例管理 ==========
  // 使用 useRef 确保缓存实例在组件生命周期内保持稳定
  const cacheRef = useRef(new NodeRenderCache());

  // ========== 性能监控状态 ==========
  const [renderCount, setRenderCount] = React.useState(0);

  // ========== 节点渲染逻辑 ==========
  /**
   * 渲染单个节点，优先使用缓存
   *
   * 🔄 渲染流程：
   * 1. 检查缓存是否存在且有效
   * 2. 缓存命中：直接返回缓存的元素
   * 3. 缓存未命中：创建新元素并缓存
   */
  const renderNode = useCallback(
    (nodeId: string) => {
      const node = nodes[nodeId];

      // 🚫 节点不存在，跳过渲染
      if (!node) {
        console.warn(`⚠️ 节点不存在: ${nodeId}`);
        return null;
      }

      // 🔍 尝试从缓存获取已渲染的元素
      // 🔍 首先尝试从缓存获取已渲染的节点（包含状态信息）
      const isCollapsed = collapsedNodes.includes(nodeId);
      const isHovered = hoveredNodeId === nodeId;
      let cachedElement = cacheRef.current.get(nodeId, node, isCollapsed, isHovered);
      if (cachedElement) {
        // ✅ 缓存命中：直接返回，避免重复渲染
        return cachedElement;
      }

      // ⚡ 缓存未命中：创建新的React元素
      const element = (
        <OKRNodeComponent
          key={nodeId} // React key，确保组件正确更新
          node={node} // 节点数据
          isHovered={isHovered} // 悬浮状态
          isCollapsed={isCollapsed} // 折叠状态
          onToggleCollapse={onToggleCollapse} // 折叠切换回调
        />
      );

      // 💾 将新创建的元素存入缓存（包含状态信息）
      cacheRef.current.set(nodeId, node, element, isCollapsed, isHovered);

      return element;
    },
    [nodes, hoveredNodeId, collapsedNodes, onToggleCollapse]
  ); // 依赖项：只有这些值变化时才重新创建回调

  // ========== 开发环境性能监控 ==========
  // 在开发环境下显示缓存统计信息
  useEffect(() => {
    setRenderCount(prev => prev + 1);

    if (import.meta.env.DEV) {
      const stats = cacheRef.current.getStats();
      console.log(`📊 渲染缓存统计 (第${renderCount + 1}次渲染):`, stats);

      // 缓存命中率过低时的优化建议
      if (parseFloat(stats.hitRate) < 50 && stats.hitCount + stats.missCount > 10) {
        console.warn("⚠️ 缓存命中率较低，检查节点数据是否频繁变化", {
          当前命中率: stats.hitRate,
          优化建议: ["检查节点数据是否有不必要的更新", "优化节点版本号生成逻辑", "考虑增加缓存大小"]
        });
      }

      // 内存使用率过高时的警告
      if (parseFloat(stats.memoryUsage) > 80) {
        console.warn("⚠️ 缓存内存使用率过高", {
          当前使用率: stats.memoryUsage,
          优化建议: ["考虑减少缓存大小", "检查是否有内存泄漏", "实现更积极的缓存清理策略"]
        });
      }
    }
  }, [visibleNodes, renderCount]); // 每次可见节点变化时输出统计

  // ========== 连接线过滤优化 ==========
  // 只渲染可见节点之间的连接线，减少SVG元素数量
  const visibleConnections = useMemo(() => {
    const visibleNodeSet = new Set(visibleNodes);
    return layout.connections.filter((conn: any) => visibleNodeSet.has(conn.from) && visibleNodeSet.has(conn.to));
  }, [layout.connections, visibleNodes]);

  // ========== JSX渲染 ==========
  return (
    <>
      {/* 🔗 渲染可见的连接线 */}
      <svg
        className="okr-tree-connections"
        style={{
          position: "absolute",
          top: 0,
          left: 0,
          width: "100%",
          height: "100%",
          pointerEvents: "none",
          zIndex: 1
        }}
      >
        <defs>
          {/* 箭头标记 */}
          <marker id="arrowhead" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
            <polygon points="0 0, 10 3.5, 0 7" fill="#d1d5db" />
          </marker>
        </defs>

        {/* 渲染连接线 - 只渲染可见节点间的连接线 */}
        {visibleConnections.map((connection: any, index: number) => (
          <path
            key={`${connection.from}-${connection.to}-${index}`}
            d={connection.path} // 使用 connection.path 作为SVG路径
            stroke="#d1d5db"
            strokeWidth="2"
            fill="none"
            markerEnd="url(#arrowhead)"
            className="okr-connection-line"
          />
        ))}
      </svg>

      {/* 🎯 渲染可见的节点 */}
      {visibleNodes.map(nodeId => {
        // 🔍 获取节点的布局位置信息
        const position = layout.positions[nodeId];
        if (!position) {
          console.warn(`⚠️ 节点位置信息不存在: ${nodeId}`);
          return null; // 位置信息不存在，跳过渲染
        }

        // 🎯 使用绝对定位渲染节点
        // 每个节点独立定位，避免相互影响和布局重排
        return (
          <div
            key={nodeId} // React key，确保列表更新正确
            style={{
              position: "absolute", // 绝对定位，脱离文档流
              left: position.x, // X坐标（相对于父容器）
              top: position.y, // Y坐标（相对于父容器）
              width: position.width, // 节点宽度
              height: position.height, // 节点高度
              zIndex: 2, // 层级：高于连接线（zIndex: 1）
              // 🚀 性能优化：启用GPU加速
              transform: "translateZ(0)",
              // ⚡ 优化渲染性能：告诉浏览器这个元素会发生变换
              willChange: "transform"
            }}
            onClick={e => {
              e.stopPropagation();
              onNodeClick?.(nodeId);
            }}
          >
            {/* 🎨 渲染节点内容（使用缓存优化） */}
            {renderNode(nodeId)}
          </div>
        );
      })}

      {/* 🐛 开发环境调试信息 */}
      {import.meta.env.DEV && import.meta.env.VITE_DEBUG_RENDERER === "true" && (
        <div
          style={{
            position: "absolute",
            top: 10,
            right: 10,
            background: "rgba(0,0,0,0.8)",
            color: "white",
            padding: "8px",
            borderRadius: "4px",
            fontSize: "12px",
            zIndex: 1000,
            fontFamily: "monospace"
          }}
        >
          <div>🎨 渲染器调试信息</div>
          <div>可见节点: {visibleNodes.length}</div>
          <div>可见连接线: {visibleConnections.length}</div>
          <div>渲染次数: {renderCount}</div>
          <div>缓存命中率: {cacheRef.current.getStats().hitRate}</div>
        </div>
      )}
    </>
  );
};

export default VirtualizedNodeRenderer;
